/**
 * jQuery jGantt Chart
 * 
 * @author dapeng.li
 */
;
(function($, win) {
	/**
	 * 获取当月最后一天的日期
	 */
	Date.prototype.getLastDateOfMonth = function() {
		return 32 - new Date(this.getFullYear(), this.getMonth(), 32).getDate();
	};
	/**
	 * 格式化日期
	 */
	Date.prototype.format = function() {
		var shortMonths = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], fullMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], formatStr = (arguments[0] || 'yyyy-MM-dd HH:mm:ss'), year = this.getFullYear(), month = this.getMonth() + 1, day = this.getDate(), hours = this.getHours(), minutes = this.getMinutes(), seconds = this.getSeconds();
		// format 'AM' or 'PM'
		if (/\s+[t]{2}$/.test(formatStr) || /\s+[t]{2}\s+/.test(formatStr)) {
			formatStr = formatStr.replace(/[t]{2}/, (hours >= 12) ? 'PM' : 'AM');
			if (hours > 12) {
				hours = hours - 12;
			}
		} else if (/\s+[t]{1}$/.test(formatStr) || /\s+[t]{1}\s+/.test(formatStr)) {
			formatStr = formatStr.replace(/[t]{1}/, (hours >= 12) ? 'P' : 'A');
			if (hours > 12) {
				hours = hours - 12;
			}
		}
		// format year
		if (/[y]{4}/.test(formatStr)) {
			formatStr = formatStr.replace(/[y]{4}/, year);
		} else {
			formatStr = formatStr.replace(/[y]{2}/, (year + '').substring(2));
		}
		// format month
		if (/[M]{4}/.test(formatStr)) {
			formatStr = formatStr.replace(/[M]{4}/, fullMonths[month - 1]);
		} else if (/[M]{3}/.test(formatStr)) {
			formatStr = formatStr.replace(/[M]{3}/, shortMonths[month - 1]);
		} else if (/[M]{2}/.test(formatStr)) {
			formatStr = formatStr.replace(/[M]{2}/, (month < 10) ? ('0' + month) : month);
		} else {
			formatStr = formatStr.replace(/[M]{1}/, month);
		}
		// format date
		if (/[d]{2}/.test(formatStr)) {
			formatStr = formatStr.replace(/[d]{2}/, (day < 10) ? ('0' + day) : day);
		} else {
			formatStr = formatStr.replace(/[d]{1}/, day);
		}
		// format hours
		if (/[H]{2}/.test(formatStr)) {
			formatStr = formatStr.replace(/[H]{2}/, (hours < 10) ? ('0' + hours) : hours);
		} else {
			formatStr = formatStr.replace(/[H]{1}/, hours);
		}
		// format minutes
		if (/[m]{2}/.test(formatStr)) {
			formatStr = formatStr.replace(/[m]{2}/, (minutes < 10) ? ('0' + minutes) : minutes);
		} else {
			formatStr = formatStr.replace(/[m]{1}/, minutes);
		}
		// format seconds
		if (/[s]{2}/.test(formatStr)) {
			formatStr = formatStr.replace(/[s]{2}/, (seconds < 10) ? ('0' + seconds) : seconds);
		} else {
			formatStr = formatStr.replace(/[s]{1}/, seconds);
		}
		return formatStr;
	};

	/**
	 * 获取日期的标准日期（年月日），不包含时分秒
	 */
	Date.prototype.getStandardDate = function() {
		return new Date(this.getFullYear(), this.getMonth(), this.getDate());
	};

	/**
	 * 获取当前日期与目标日期间隔的天数
	 */
	Date.prototype.getIntervalDays = function(target) {
		return Math.abs((this.getStandardDate() - target.getStandardDate()) / 86400000);
	};

	/**
	 * 获取两个日期间隔的天数
	 */
	var getIntervalDays = function(start, end) {
		return start.getIntervalDays(end);
	},

	/**
	 * 创建单元格
	 */
	createDivCell = function(cell, text, width, borderWidth, title) {
		return '<div class="' + cell + '" style="width:' + width + 'px;border-right-width:' + borderWidth + 'px" title="' + (title || '') + '">' + text + '</div>';
	},

	/**
	 * 获取随机字符串
	 */
	getRandomId = function() {
		return Math.random().toString(36).substring(2);
	},

	/**
	 * 进度条id转行id
	 */
	barId2RowId = function(barId) {
		return barId.replace('-processbar-', '-datarow-');
	},

	/**
	 * 行id转进度条id
	 */
	rowId2BarId = function(rowId) {
		return rowId.replace('-datarow-', '-processbar-');
	};

	/**
	 * JGantt构造函数
	 * 
	 * @param start The start date
	 * @param end The end date
	 * @param ele dom
	 * @param obj {}
	 */
	var JGantt = function(start, end, ele, obj) {
		$.extend(this, {
			scale: 1, // 一天占用的格子数
			processParent: {}, // 父进度集key: parentBarId, value: ['processBarId1', 'processBarId2', 'processBarId3', ...]
			processSet: {}, // 进度集key: barId, value: {}
			processData: {}, // 行数据集key: rowId, value: {}
			childrenField: 'children', // 子数据集字段
			updateNextBar: true, // 联动更新后续进度
			processCreated: $.noop, // 进度创建完回调 function(barId, barData) {}
			processUpdated: $.noop, // 进度更新玩回调 function(barId, barData,updateNextBar) {}
			processRemoved: $.noop, // 进度删除前回调 function(barId, barData) {}
			processChanged: $.noop, // 进度操作后/前回调 function(type, barId, barData) {}
			scrollLoad: true, // 时间横向滚动加载
			scrollLoaded: $.noop, // 横向加载回调
			columns: [], // 数据列 [{field: '', text: ''}, {...}, {...}, ...]
			model: 'ymwd' // y-年份 m-月份 w-星期 d-日期
		}, obj, true);
		// 没有设置开始时间，则默认从当前日期开始
		if (!start) {
			start = new Date();
		}
		// 如果没有结束时间或结束小于开始，则设置起止时间间隔两个月
		if (!end || end < start) {
			end = new Date(start);
			end.setDate(1);
			end.setMonth(end.getMonth() + 2);
			if (end.getLastDateOfMonth() < start.getDate()) {
				end.setDate(end.getLastDateOfMonth());
			} else {
				end.setDate(start.getDate() - 1);
			}
		}
		$.extend(this, {
			start: start,
			end: end
		});
		// 格子范围1-6
		this.scale = this.scale && this.scale > 0 ? (this.scale > 6 ? 6 : this.scale) : 1;
		// 格子换算成像素 * 24
		this._scale = this.scale * 24;

		var rowsCreator = {
			y: '_createYearRow',
			m: '_createMonthRow',
			w: '_createWeekRow',
			d: '_createDateRow'
		};

		this.rowsCreator = [];
		for (var index = 0; index < this.model.length; index++) {
			if (this.rowsCreator.indexOf(rowsCreator[this.model[index]]) == -1) {
				this.rowsCreator.push(rowsCreator[this.model[index]]);
			}
		}
		if (!ele.id) {
			ele.id = getRandomId();
		}
		this.eleId = ele.id;
		this.init(ele);
	};

	var months = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月']; // ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
	var dayOfWeeks = ['日', '一', '二', '三', '四', '五', '六']; // ["S", "M", "T", "W", "T", "F", "S"];

	JGantt.prototype = {
		/**
		 * 构造函数
		 */
		constructor: JGantt,
		/**
		 * 获取列表面板
		 */
		getGridPanel: function() {
			return this.$left_content;
		},
		/**
		 * 获取视图面板
		 */
		getGraphPanel: function() {
			return this.$right_content;
		},
		/**
		 * 获取列表行数
		 */
		getRowLength: function() {
			return this.getGridPanel().children('.dataRow').length;
		},
		/**
		 * rowId
		 */
		getRowId: function(rowIndex) {
			return this.eleId + '-datarow-' + rowIndex;
		},
		/**
		 * barId
		 */
		getBarId: function(rowIndex) {
			return this.eleId + '-processbar-' + rowIndex;
		},
		/**
		 * 获取开始和结束时间持续的天数
		 */
		getDays: function() {
			return getIntervalDays(this.start, this.end) + 1;
		},
		/**
		 * 设置/获取属性
		 */
		option: function(key, value) {
			if (value !== undefined) {
				this[key] = value;
			} else {
				if ($.isPlainObject(key)) {
					$.extend(this, key);
				} else {
					return this[key];
				}
			}
		},
		/**
		 * 视图初始化，仅执行一次
		 */
		init: function(ele) {
			// 局部变量
			var gantt = this, width = gantt.getDays() * gantt._scale + 20, headerHeight = gantt.rowsCreator.length * 25 - 1, leftWidth = 0;
			$.each(this.columns, function() {
				leftWidth += (this.width + 1);
			});
			leftWidth -= 1;
			// 左右面板模板
			var $leftPanelTemp = $('<div class="jgantt-panel jgantt-left"/>'), $rightPanelTemp = $('<div class="jgantt-panel jgantt-right"/>');
			// 检查左右面板宽度
			if (leftWidth < $leftPanelTemp.width() && leftWidth > 0) {
				$leftPanelTemp.width(leftWidth);
				$rightPanelTemp.css({
					marginLeft: leftWidth
				});
			}
			// 改变精度按钮
			var $scaleAdd = $('<div class="scale-icon scale-add">+</div>').attr('disabled', gantt.scale == 6).click(function() {
				if ($(this).attr('disabled')) {
					return false;
				}
				gantt.addScale();
				setScaleIconStatus();
			}), $scaleSub = $('<div class="scale-icon scale-sub">-</div>').attr('disabled', gantt.scale == 1).click(function() {
				if ($(this).attr('disabled')) {
					return false;
				}
				gantt.subtractScale();
				setScaleIconStatus();
			}), setScaleIconStatus = function() {
				$scaleAdd.attr('disabled', gantt.scale == 6);
				$scaleSub.attr('disabled', gantt.scale == 1);
			};

			// 表头、表中、表脚以及滚动条
			var $header = $('<div class="jgantt-header"/>').css({
				width: '100%',
				height: headerHeight + 1
			}), $content = $('<div class="jgantt-content"/>').css({
				top: headerHeight + 1
			}), $footer = $('<div class="jgantt-footer"/>').css({
				width: '100%',
				height: 16
			}), $leftScrollBar = $('<div class="gantt-scrollBar"/>').width(leftWidth), $rightScrollBar = $leftScrollBar.clone().width(width);
			// 表头部分
			this.$left_header = $('<div class="header"/>').css({
				width: leftWidth,
				height: headerHeight
			}).appendTo($leftPanelTemp.clone().appendTo($header));
			this.$right_header = $('<div class="header"/>').css({
				width: width,
				height: headerHeight
			}).appendTo($rightPanelTemp.clone().appendTo($header));
			// 正编辑的进度条
			var $editorialBar = undefined, editorialObj = {}, editStatus = false, disableEdit = function() {
				if (editStatus && $editorialBar && $editorialBar.attr('id')) {
					gantt.updateProcessBar($editorialBar.attr('id'));
					$editorialBar.removeClass('moving');
				}
				$scaleAdd.fadeIn();
				$scaleSub.fadeIn();
				editStatus = false;
				$editorialBar = undefined;
				editorialObj = {};
			};
			// 数据部分
			this.$left_content = $('<div class="content"/>').css({
				width: leftWidth
			}).appendTo($leftPanelTemp.clone().appendTo($content));
			// 甘特图部分
			this.$right_content = $('<div class="content"/>').css({
				width: width
			}).on('dblclick', '.jgantt-bar', function() {
				return false;
			}).on('mouseleave', disableEdit).on('mousedown', '.resize-left, .move-center, .resize-right', function(e) {
				if (!$(this).parent().attr('disabled')) {
					var event = e || win.event;
					$editorialBar = $(this).parent(), type = this.className, scrollMaxLeft = gantt.$rightScrollBar.parent()[0].scrollWidth - gantt.$rightScrollBar.parent().width();
					editorialObj = {
						pageX: event.pageX,
						originalLeft: parseInt($editorialBar[0].style.left),
						originalWidth: $editorialBar.width(),
						editType: type,
						scrollMaxLeft: scrollMaxLeft,
						scrollProportion: scrollMaxLeft / gantt.$rightScrollBar.parent()[0].scrollWidth
					};
					$scaleAdd.hide();
					$scaleSub.hide();
				}
			}).appendTo($rightPanelTemp.clone().appendTo($content)).append('<div class="occupancy"/>');
			// 记录滚动到最右端的时间
			var scrollTime = 0, scrollStatus = false, getOffset = function(ele) {
				var top = ele.offsetTop, left = ele.offsetLeft, width = ele.offsetWidth, height = ele.offsetHeight;
				while (ele.offsetParent) {
					ele = ele.offsetParent;
					if (win.navigator.userAgent.indexOf('MSTE 8') != -1) {
						top += ele.offsetTop;
						left += ele.offsetLeft;
					} else {
						top += ele.offsetTop + ele.clientTop;
						left += ele.offsetLeft + ele.clientLeft;
					}
				}
				return {
					left: left,
					top: top,
					bottom: top + height,
					right: left + width
				}
			};
			// 底部滚动条部分
			$footer.append($leftPanelTemp.clone().scroll(function() {
				gantt.$left_header.parent().scrollLeft(this.scrollLeft);
				gantt.$left_content.parent().scrollLeft(this.scrollLeft);
			}).append($leftScrollBar)).append($rightPanelTemp.clone().scroll(function() {
				gantt.$right_header.parent().scrollLeft(this.scrollLeft);
				gantt.$right_content.parent().scrollLeft(this.scrollLeft);
				var scrollMaxLeft = gantt.$rightScrollBar.parent()[0].scrollWidth - gantt.$rightScrollBar.parent().width();
				// 滚动到最右端时，记录时间、滚动状态
				if (scrollMaxLeft == this.scrollLeft) {
					scrollTime = new Date().getTime();
					scrollStatus = true;
				} else {
					scrollTime = 0;
					scrollStatus = false;
				}
			}).mousedown(function(e) {
				var offset = getOffset(this);
				// 鼠标点击区域在滚动条最右端按钮且已经滚动到最右端时时，记录时间、滚动状态
				if (e.pageX >= offset.right - 16 && e.pageX <= offset.right && e.pageY >= offset.top && e.pageY <= offset.top + 16) {
					scrollTime = new Date().getTime();
					scrollStatus = true;
				}
				return false;
			}).mouseup(function(e) {
				// 当处于滚动状态，且鼠标按压时间超过0.4秒时，如果设置了滚动加载，则滚动加载
				if (scrollStatus) {
					if (gantt.scrollLoad && new Date().getTime() - scrollTime > 400) {
						var newEnd = new Date(gantt.end);
						// 设置日期为下个月1号
						newEnd.setDate(1);
						newEnd.setMonth(newEnd.getMonth() + 1);
						// 如果结束日期不小于下一月最后一天，则设置新结束日期为下个月最后一天，否则设置为下一月同一天
						if (newEnd.getLastDateOfMonth() <= gantt.end.getDate() || gantt.end.getLastDateOfMonth() === gantt.end.getDate()) {
							newEnd.setDate(newEnd.getLastDateOfMonth());
						} else {
							newEnd.setDate(gantt.end.getDate());
						}
						if ($.isFunction(gantt.scrollLoadCall)) {
							var newStart = new Date(gantt.end);
							newStart.setDate(newStart.getDate() + 1);
							gantt.scrollLoadCall.call(gantt, newStart, newEnd);
						}
						gantt.end = newEnd;
						gantt._repaint(false);
					}
					scrollStatus = false;
					scrollTime = 0;
				}
				return false;
			}).append($rightScrollBar));
			this.$rightScrollBar = $rightScrollBar;
			this.createGridHeader();
			// 将组件追加到元素中
			$(ele).addClass('jgantt').append($header).append($content).append($footer).append($('<div class="divide-line"/>').css({
				left: $leftPanelTemp.width()
			})).append($scaleAdd).append($scaleSub);
			// 处理编辑事件
			$(document).on('mouseup', disableEdit).on('mousemove', function(e) {
				// 可编辑状态
				if ($editorialBar) {
					editStatus = true;
					var event = e || win.event, pageX = event.pageX, originalPageX = editorialObj.pageX;
					var originalLeft = editorialObj.originalLeft, originalWidth = editorialObj.originalWidth;
					var difference = pageX - originalPageX;
					switch (editorialObj.editType) {
						case 'resize-left' :
							if (originalLeft + difference < 0) {
								$editorialBar.addClass('moving').css({
									left: 0,
									width: originalWidth + originalLeft
								});
							} else {
								$editorialBar.addClass('moving').css({
									left: originalLeft + difference,
									width: originalWidth - difference
								});
							}
							break;
						case 'move-center' :
							if (originalLeft + difference < 0) {
								$editorialBar.addClass('moving').css({
									left: 0
								});
							} else if (originalLeft + difference + originalWidth > width - 20) {
								$editorialBar.addClass('moving').css({
									left: width - 20 - originalWidth
								});
							} else {
								$editorialBar.addClass('moving').css({
									left: originalLeft + difference
								});
							}
							break;
						case 'resize-right' :
							if (originalLeft + difference + originalWidth > width - 20) {
								$editorialBar.addClass('moving').css({
									width: width - 20 - originalLeft
								});
							} else {
								$editorialBar.addClass('moving').css({
									width: originalWidth + difference
								});
							}
							break;
					}
				}
			});
		},
		/**
		 * 重新绘制甘特图部分，主要在改变精度时执行
		 */
		_repaint: function(flag) {
			var gantt = this, width = gantt.getDays() * gantt._scale + 20;
			gantt.$right_header.width(width);
			gantt.$right_content.width(width);
			gantt.$rightScrollBar.width(width);
			// 绘制甘特表头
			gantt.$right_header.empty().append('<div class="occupancy"/>');
			$.each(gantt.rowsCreator, function() {
				gantt[this].call(gantt);
			});
			if (flag === false) {
				return;
			}
			// 更新进度条
			$.each(gantt.processSet, function(key, value) {
				gantt.updateProcessBar(key, gantt.getProcessData(key), false);
			});
		},
		/**
		 * 增加精度
		 */
		addScale: function() {
			if (this.scale < 6) {
				this.scale++;
				this._scale = this.scale * 24;
				this._repaint();
			}
		},
		/**
		 * 减小精度
		 */
		subtractScale: function() {
			if (this.scale > 1) {
				this.scale--;
				this._scale = this.scale * 24;
				this._repaint();
			}
		},
		/**
		 * 设置精度
		 */
		setScale: function(scale) {
			if (!isNaN(scale) && 60 % scale === 0) {
				this.scale = scale;
				this._scale = this.scale * 24;
				this._repaint();
			}
		},
		/**
		 * 生成表头
		 */
		createGridHeader: function() {
			var gantt = this;
			// 绘制数据表头
			this.$left_header.empty();
			this.createDataHeader();
			// 绘制甘特表头
			this.$right_header.empty().append('<div class="occupancy"/>');
			$.each(this.rowsCreator, function() {
				gantt[this].call(gantt);
			});
		},
		/**
		 * 生成数据表头
		 */
		createDataHeader: function() {
			var gantt = this;
			$.each(this.columns, function(index, column) {
				var $hearderCell = $(createDivCell('headerCell', column.text, column.width, index === gantt.columns.length - 1 ? 0 : 1, column.title || column.text));
				// checkbox 全选
				if (column.type === '_checkbox') {
					$('<input type="checkbox"/>').appendTo($hearderCell).on('change', function() {
						var checked = this.checked;
						$('.dataRow > .dataCell:nth-child(' + (index + 1) + ') > [type=checkbox]:not([disabled])', gantt.$left_content).each(function() {
							this.checked = checked;
						});
					});
				}
				// 附加的表头单元格转化
				if ($.isFunction(column.render)) {
					column.render($hearderCell);
				}
				$hearderCell.css({
					lineHeight: gantt.rowsCreator.length * 25 - 1 + 'px'
				}).appendTo(gantt.$left_header);
			});
		},
		/**
		 * 生成年份行
		 */
		_createYearRow: function() {
			var $yearRow = $('<div class="jgantt-row yearRow"/>'), startYear = this.start.getFullYear(), endYear = this.end.getFullYear(), scale = this._scale, createCell = function(year, interval) {
				return createDivCell('yearCell', year, interval * scale - 1, 1, year);
			};
			if (endYear === startYear) {
				$yearRow.append(createCell(startYear, this.getDays()));
			} else {
				for (var year = startYear; year <= endYear; year++) {
					if (year < endYear) {
						if (year === startYear) {
							// 这是结束日期为当年的12月31日
							var endDate = new Date(year, 11, 31);
							$yearRow.append(createCell(year, getIntervalDays(this.start, endDate) + 1));
						} else {
							// 中间整年部分判断是否闰年来确定天数
							var interval = (year % 4 === 0 && year % 100 !== 0 || year % 400 === 0) ? 366 : 365;

							$yearRow.append(createCell(year, interval));
						}
					} else {
						// 设置开始时间为当年的1月1日
						var startDate = new Date(year, 0, 1);
						$yearRow.append(createCell(year, getIntervalDays(startDate, this.end) + 1));
					}
				}
			}
			$yearRow.hide().appendTo(this.$right_header).fadeIn();
		},
		/**
		 * 生成月份行
		 */
		_createMonthRow: function($monthRow) {
			var $monthRow = $('<div class="jgantt-row monthRow"/>'), startDate = new Date(this.start.getTime()), scale = this._scale, createCell = function(month, interval, title) {
				return createDivCell('monthCell', months[month], interval * scale - 1, 1, title);
			}, getNextMonth = function(date) {
				return new Date(date.getFullYear(), date.getMonth() + 1, 1);
			};

			var start = startDate.getDate();

			startDate.setMonth(startDate.getMonth() + 1);
			startDate.setDate(0);
			var isOver = startDate > this.end;

			var end = startDate > this.end ? this.end.getDate() : startDate.getDate();
			$monthRow.append(createCell(startDate.getMonth(), end - start + 1, startDate.getFullYear() + '-' + (startDate.getMonth() + 1)));

			while (!isOver) {
				startDate.setFullYear(startDate.getFullYear(), startDate.getMonth() + 1, 1);
				isOver = getNextMonth(startDate) > this.end;
				end = isOver ? this.end.getDate() : startDate.getLastDateOfMonth();
				$monthRow.append(createCell(startDate.getMonth(), end, startDate.getFullYear() + '-' + (startDate.getMonth() + 1)));
			}
			$monthRow.hide().appendTo(this.$right_header).fadeIn();
		},
		/**
		 * 生成星期行
		 */
		_createWeekRow: function() {
			var $weekRow = $('<div class="jgantt-row weekRow"/>'), startDate = new Date(this.start.getTime()), scale = this._scale, createCell = function(cell, text, title) {
				return createDivCell(cell, text, scale - 1, 1, title);
			}, getNextDate = function(date) {
				return new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1);
			}, isOver = false, totalLeft = 0;
			while (!isOver) {
				isOver = getNextDate(startDate) > this.end;
				$weekRow.append(createCell('weekCell', dayOfWeeks[startDate.getDay()], startDate.format('yyyy-MM-dd')));
				startDate.setDate(startDate.getDate() + 1);
				totalLeft += scale;
			}
			$weekRow.hide().appendTo(this.$right_header).fadeIn();
		},
		/**
		 * 生成日期行
		 */
		_createDateRow: function() {
			var $dateRow = $('<div class="jgantt-row dateRow"/>'), startDate = new Date(this.start.getTime()), scale = this._scale, createCell = function(cell, text, title) {
				return createDivCell(cell, text, scale - 1, 1, title);
			}, getNextDate = function(date) {
				return new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1);
			}, isOver = false, totalLeft = 0;
			while (!isOver) {
				isOver = getNextDate(startDate) > this.end;
				$(createCell('dateCell', startDate.getDate(), startDate.format('yyyy-MM-dd'))).attr({
					date: startDate.format('yyyy-MM-dd'),
					pleft: totalLeft
				}).appendTo($dateRow);
				startDate.setDate(startDate.getDate() + 1);
				totalLeft += scale;
			}
			$dateRow.hide().appendTo(this.$right_header).fadeIn();
		},
		/**
		 * 递归更新父进度条
		 */
		updatePaternalBar: function(barId) {
			var gantt = this, $dataRow = gantt.getRow(barId2RowId(barId)), _parent = $dataRow.attr('_parent');
			// 如果有_parent属性则属于子行，需要缓存关系
			if (_parent) {
				// 找到对应的父行
				var $parentRow = gantt.getRow(_parent), _parentKey = rowId2BarId(_parent), obj, start, end;
				$.each(this.processParent[_parentKey] || [], function(index, key) {
					obj = gantt.getProcessData(key);
					if (!obj) {
						return true;
					}
					if (!start) {
						start = obj.start;
					} else {
						start = obj.start < start ? obj.start : start;
					}
					if (!end) {
						end = obj.end;
					} else {
						end = obj.end > end ? obj.end : end;
					}
				});
				if (start && end) {
					// 有子级进度时，新建或更新父进度条
					this.updateProcessBar(_parentKey, {
						start: start,
						end: end,
						rowIndex: gantt.rowId2RowIndex(_parent),
						disabled: $parentRow.is('.rootRow'),
						rootBar: $parentRow.is('.rootRow')
					});
				} else {
					// 没有子级进度时删除父级进度条
					this.removeProcessBar(_parentKey);
				}
				// 继续向父级递归，直至顶级
				this.updatePaternalBar(_parentKey);
			}
		},
		/**
		 * 遍历更新后续所有兄弟进度条，最后一次性更新父级进度条
		 */
		updateBrotherlyBar: function(barId) {
			// 该进度条对应的数据行
			var gantt = this, $dataRow = gantt.getRow(barId2RowId(barId)), _parent = $dataRow.attr('_parent');
			// 如果有_parent属性,则可能存在兄弟进度条
			if (_parent) {
				var obj, start, end, currentIndex;
				$.each(this.processParent[rowId2BarId(_parent)], function(index, key) {
					if (currentIndex !== undefined && obj && gantt.processSet[key]) {
						var next = gantt.getProcessData(key), difference = next.start - obj.end;
						gantt.updateProcessBar(key, {
							start: new Date(next.start.getTime() - difference),
							end: new Date(next.end.getTime() - difference)
						}, false);
					}
					if (key === barId) {
						currentIndex = index;
					}
					if (gantt.processSet[key]) {
						obj = gantt.getProcessData(key);
					}
				});
				this.updatePaternalBar(barId);
			}
		},
		/**
		 * 获取进度条位置
		 */
		getBarPosition: function(data) {
			var gantt = this, scale = gantt._scale, left = (getIntervalDays(gantt.start, data.start)) * scale, width = (getIntervalDays(data.start, data.end)) * scale;
			left = left + scale / 24 * data.start.getHours();
			width = width + scale / 24 * (data.end.getHours() - data.start.getHours());
		},
		/**
		 * 新建进度条，不更新父级、兄弟级进度
		 */
		createProcessBar: function(obj) {
			var gantt = this, scale = gantt._scale, rowIndex = obj._rowIndex || obj.rowIndex, barId = gantt.getBarId(rowIndex);
			var top = rowIndex * 24, left = (getIntervalDays(gantt.start, obj.start)) * scale, width = (getIntervalDays(obj.start, obj.end)) * scale;
			// 将进度数据和行数据合并
			var data = gantt.getProcessData(rowIndex);
			$.extend(data, obj, true);
			// 缓存进度ID
			this.processSet[barId] = true;
			// 进度条
			var $bar = $('<div class="jgantt-bar">').attr({
				id: barId,
				disabled: data.disabled || false,
				title: data.title || data.label || ''
			}).css($.extend({
				top: top,
				left: left + scale / 24 * data.start.getHours()
			}, data.css || {})).animate({
				width: width + scale / 24 * (data.end.getHours() - data.start.getHours())
			}, 300).append('<div class="resize-left"/>').append('<div class="move-center"/>').append('<div class="resize-right"/>')
			.append($('<label class="bar-label"/>').append(data.label || '')).appendTo(this.$right_content);

			if ($.isFunction(data.render)) {
				data.render($bar);
			}
			// 父进度
			if (!data._parent) {
				$bar.addClass('rootBar');
			}
			// 创建后的回调
			this.processCreated(barId, data);
			// 改变后的回调
			this.processChanged('create', barId, data);
			return barId;
		},
		/**
		 * 更新进度条【如果进度条不存在但是有进度对象时自动创建进度条】，更新兄弟级进度条
		 */
		updateProcessBar: function(key, obj) {
			var gantt = this, $bar = gantt.getBar(key), data = gantt.getProcessData(key);
			if (!$bar.length) {
				if (obj) {
					gantt.createProcessBar(obj);
					return false;
				}
			} else {
				var scale = gantt._scale;
				if (obj) {
					// 改变绑定的对象时
					if (obj.start && obj.end) {
						var left = (getIntervalDays(gantt.start, obj.start)) * scale, width = (getIntervalDays(obj.start, obj.end)) * scale;
						$bar.animate({
							left: left + scale / 24 * obj.start.getHours(),
							width: width + scale / 24 * (obj.end.getHours() - obj.start.getHours())
						}, 300);
					}
					if (obj.label) {
						$('>.bar-label', $bar).text(obj.label);
					}
					if (obj.css) {
						$bar.css(obj.css);
					}
					$.extend(data, obj);
				} else {
					// 仅改变视图（拖拽或重置宽度）时
					var left = $bar.position().left, width = $bar.width(), interval = Math.floor(left / scale);
					// 分别计算开始日期和结束日期
					var start = new Date(gantt.start);
					start.setDate(start.getDate() + Math.floor(left / scale));
					var end = new Date(start);
					end.setDate(start.getDate() + Math.floor(width / scale));
					// 设置精确的小时
					var excessLeft = left % scale, excessWidth = width % scale;
					start.setHours(Math.floor(excessLeft / (scale / 24)));
					end.setHours(Math.floor((excessLeft + excessWidth) / (scale / 24)));
					// 设置精确的分钟
					excessLeft = excessLeft % (scale / 24), excessWidth = excessWidth % (scale / 24);
					if (excessLeft || excessWidth) {
						start.setMinutes(excessLeft * 60 * 24 / scale);
						end.setMinutes((excessLeft + excessWidth) * 60 * 24 / scale);
					}
					data.start = start;
					data.end = end;
				}
			}
			// 更新时回调
			this.processUpdated(key, data, arguments[3]);
			// 改变后的回调
			this.processChanged('update', key, data);
			// 更新兄弟进度条、改变精度时不递归更新
			if (arguments[2] !== false) {
				if (this.updateNextBar) {
					this.updateBrotherlyBar(key);
				} else {
					this.updatePaternalBar(key);
				}
			}
		},
		/**
		 * 删除进度条，仅更新父级进度
		 */
		removeProcessBar: function(key) {
			var $bar = this.getBar(key), data = this.getProcessData(key);
			// 删除时回调
			if ($.isFunction(this.processRemoved)) {
				this.processRemoved(key, data);
			}
			// 改变后的回调
			if ($.isFunction(this.processChanged)) {
				this.processChanged('remove', key, data);
			}
			// 删除操作
			this.getBar(key).removeData().remove();
			if (!delete this.processSet[key]) {
				this.processSet[key] = undefined;
			}
			delete data.start;
			delete data.end;
			this.updatePaternalBar(key);
		},
		/**
		 * 创建行
		 */
		_createRow: function(obj, rowIndex, parentRowId) {
			var gantt = this, rowId = gantt.getRowId(rowIndex), $row = $('<div class="dataRow"/>').attr({
				id: rowId,
				rowIndex: rowIndex
			});
			// 设置_rowIndex_属性
			$.extend(obj, {
				_rowIndex: rowIndex
			}, true);
			// 有父节点时设置相关属性
			if (parentRowId) {
				$row.attr('_parent', parentRowId);
				var key = rowId2BarId(parentRowId);
				if (!this.processParent[key]) {
					this.processParent[key] = [];
				}
				this.processParent[key].push(rowId2BarId(rowId));
			} else {
				$row.addClass('rootRow');
			}
			// 遍历列，填充单元格
			$.each(this.columns, function(index, column) {
				var $dataCell = $(createDivCell('dataCell', obj[column.field] || '', column.width, index === gantt.columns.length - 1 ? 0 : 1, obj[column.field] || ''));
				// checkbox
				if (column.type === '_checkbox') {
					$('<input type="checkbox"/>').appendTo($dataCell.empty()).val(obj[column.field]);
				}
				if (column.field === '_index') {
					$dataCell.text(rowIndex + 1);
				}
				// 附加的数据单元格转化
				if ($.isFunction(column.dataRender)) {
					column.dataRender($row, $dataCell, obj, column);
				}
				$row.append($dataCell.attr({
					field: column.field || ''
				}));
			});
			return $row;
		},
		/**
		 * 填充数据行
		 */
		createDataRow: function(obj, parentRowId) {
			if (!obj) {
				return;
			}
			var gantt = this, rowIndex = gantt.getRowLength(), rowId = gantt.getRowId(rowIndex), $row = gantt._createRow(obj, rowIndex, parentRowId);
			gantt.getGraphPanel().height((rowIndex + 1) * gantt._scale);
			$row.appendTo(gantt.$left_content);
			this.processData['process-' + rowIndex] = obj;
			if (obj.start && obj.end) {
				gantt.createProcessBar(obj);
			}
			$.each(obj[this.childrenField] || [], function() {
				this._parent = obj;
				gantt.createDataRow(this, rowId);
			});
		},
		/**
		 * 插入行前置操作：1、将数据插入data
		 */
		_insertData: function(rowIndex, rowData) {
			// 没有插入行的序号、序号小于0或者没有行数据
			if (rowIndex === undefined || rowIndex < 0 || !rowData) {
				return false;
			}
			var gantt = this, isBreak = false, insertIndex = rowIndex - 1,
			/**
			 * 插入数据
			 */
			insert = function(array, index, rowData) {
				if (rowData instanceof Array) {
					var prarms = [index + 1, 0].concat(rowData);
				} else {
					var prarms = [index + 1, 0, rowData];
				}
				Array.prototype.splice.apply(array, prarms);
			};
			/**
			 * 找到对应的位置插入数据
			 */
			(function insertData(array, rowIndex, rowData) {
				$.each(array, function(index, obj) {
					if (obj._rowIndex === rowIndex) {
						insert(array, index, rowData);
						isBreak = true;
					} else {
						var children = obj[gantt.childrenField];
						if (children && (children instanceof Array) && children.length) {
							insertData(children, rowIndex, rowData);
						}
					}
					if (isBreak) {
						return false;
					}
				});
			})(gantt.data, rowIndex, rowData);
			var totalLines = gantt._updateConnection();
			gantt._updateView(rowIndex, rowData, totalLines);
		},
		/**
		 * 更新父子关系
		 */
		_updateConnection: function() {
			var gantt = this, _index = 0;
			gantt.processData = {};
			gantt.processParent = {};
			(function setIndex(array, parent) {
				$.each(array, function(index, obj) {
					obj._rowIndex = _index;
					if (parent) {
						obj._parent = parent;
						gantt.processParent[gantt.getBarId(parent._rowIndex)].push(gantt.getBarId(obj._rowIndex));
					}
					gantt.processData['process-' + obj._rowIndex] = obj;
					_index += 1;
					var children = obj[gantt.childrenField];
					if (children && children.length) {
						gantt.processParent[gantt.getBarId(obj._rowIndex)] = [];
						setIndex(children, obj);
					}
				});
			})(gantt.data);
			// 返回总行数
			return _index;
		},
		/**
		 * 更新视图
		 */
		_updateView: function(rowIndex, rowData, totalLines) {
			if (isNaN(rowIndex) || !rowData) {
				return;
			}
			var gantt = this, rowsNum = 1, processSet = $.extend({}, gantt.processSet), rows = [];
			gantt.processSet = {};
			if (rowData instanceof Array) {
				rowsNum = rowData.length;
				rows = rowData;
			} else {
				rows.push(rowData);
			}
			var $rows = gantt.getGridPanel().children('.dataRow'), $divide;
			// 从后向前更新行及对应的进度条
			for (var index = totalLines - 1; index >= 0; index--) {
				if (index <= rowIndex) {
					if (processSet[gantt.getBarId(index)]) {
						gantt.processSet[gantt.getBarId(index)] = true;
					}
					continue;
				}
				// 更新row的属性值
				var $row = $($rows[index]), $divide = $row;
				$row.attr({
					rowIndex: index + rowsNum,
					id: gantt.getRowId(index + rowsNum)
				});
				$row.find('.dataCell[field="_index"]').text(index + rowsNum + 1);
				if ($row.attr('_parent')) {
					$row.attr('_parent', gantt.getRowId(gantt.getProcessData(index + rowsNum)._parent._rowIndex));
				}
				// 更新进度的高度
				if (processSet[gantt.getBarId(index)]) {
					gantt.getBar(gantt.getBarId(index)).attr({
						id: gantt.getBarId(index + rowsNum)
					}).css({
						top: (index + rowsNum) * 24
					});
					gantt.processSet[gantt.getBarId(index + rowsNum)] = true;
				}
			}
			// 插入新行
			$.each(rows, function(index, obj) {
				var $_row = gantt._createRow(obj, index + rowIndex + 1, gantt.getRowId(obj._parent._rowIndex)).initUI();
				if ($divide.length) {
    				$_row.insertBefore($divide);
				} else {
				    gantt.getGridPanel().append($_row);
				}
			});
			gantt.getGraphPanel().height(totalLines * gantt._scale);

		},
		/**
		 * 插入行
		 */
		insertRow: function(rowIndex, data) {
			this._insertData(rowIndex, data);
		},
		/**
		 * 追加行
		 */
		appendRow: function() {
			// do nothing
		},
		/**
		 * 删除行
		 */
		deleteRow: function(rowIndex) {
			// do nothing
		},
		/**
		 * 加载数据
		 */
		loadData: function(ops) {
			if (!this.source && !ops.url) {
				return;
			}
			if (typeof this.source === 'string' || ops.url) {
				var url = this.source || ops.url, data;
				$.ajax({
					type: 'POST',
					url: url,
					data: ops || {},
					dataType: 'json',
					cache: false,
					success: function(json) {
						data = json;
					}
				});
				this.data = data || [];
			} else if (typeof this.source === 'function') {
				this.data = this.source();
			} else {
				console.error("Con't parse the data source.");
			}
		},
		/**
		 * 填充数据
		 */
		fillData: function(data) {
			var gantt = this;
			gantt.data = gantt.data || [];
			// 如果参数是数组
			if (data && (data instanceof Array)) {
				gantt.data = data;
			} else if (data && $.isPlainObject(data)) {
				gantt.data = [];
				gantt.data.push(data);
			}
			$.each(gantt.data, function() {
				gantt.createDataRow(this);
			});
		},
		/**
		 * 清除数据
		 */
		clearData: function() {
			this.data = [];
			this.initView();
		},
		/**
		 * 初始化视图
		 */
		initView: function() {
			this.$left_content.children('.dataRow').removeData().remove();
			this.$right_content.children('.jgantt-bar').removeData().remove();
			this.processParent = {};
			this.processSet = {};
			this.processData = {};
			this.$right_content.height(0);
		},
		/**
		 * 获取列表数据
		 */
		getData: function() {
			return this.data;
		},
		/**
		 * 获取gantt对象
		 */
		getGantt: function() {
			return this;
		},
		/**
		 * 获取进度条
		 */
		getBar: function(barId) {
			return this.$right_content.find('#' + barId);
		},
		/**
		 * 获取行
		 */
		getRow: function(rowId) {
			return this.$left_content.find('#' + rowId);
		},
		/**
		 * 进度条对应的行index
		 */
		barId2RowIndex: function(barId) {
			return parseInt(barId.substring((this.eleId + '-processbar-').length));
		},
		/**
		 * 获取行的index
		 */
		rowId2RowIndex: function(rowId) {
			return parseInt(rowId.substring((this.eleId + '-datarow-').length));
		},
		/**
		 * 获取行数据，参数可以为 rowId、barId或者rowIndex
		 */
		getProcessData: function(key) {
			if (!isNaN(key)) {
				return this.processData['process-' + key];
			} else if (key.indexOf('-processbar-') >= 0) {
				return this.processData['process-' + this.barId2RowIndex(key)];
			} else if (key.indexOf('-datarow-') >= 0) {
				return this.processData['process-' + this.rowId2RowIndex(key)];
			} else {
				return undefined;
			}
		},
		/**
		 * 更新行数据
		 */
		updateProcessData: function(key, obj) {
			if ($.isPlainObject(obj)) {
				$.extend(this.getProcessData(key), obj, true);
			}
		}
	};

	/**
	 * jGantt plugin
	 */
	$.fn.jGantt = function() {
		if (arguments.length === 0 || $.isPlainObject(arguments[0])) {
			var settings = {
				start: new Date(new Date().getFullYear(), 0, 1),
				end: new Date(new Date().getFullYear(), 11, 31),
				scale: 1,
				data: []
			};
			$.extend(settings, arguments[0] || {}, true);
			var interval = JGantt.prototype.getDays.apply(settings);
			if (interval < 30) {
				settings.scale = Math.ceil(30 / interval);
			}
			return this.each(function() {
				this._jGantt = new JGantt(settings.start, settings.end, this, settings);
			});
		} else if (typeof arguments[0] === "string") {
			var fun = arguments[0], args = Array.prototype.slice.call(arguments, 1), returnValue;
			this.each(function() {
				if (!this._jGantt) {
					console.error('JGantt is not initiatory.');
					return false;
				}
				if ($.isFunction(this._jGantt[fun])) {
					// 有返回值时返回第一个
					returnValue = this._jGantt[fun].apply(this._jGantt, args);
					if (returnValue) {
						return false;
					}
				} else {
					console.error('Function name "' + fun + '" is not existing.');
				}
			});
			// 没有返回值时返回jQuery对象
			if (!returnValue) {
				return this;
			} else {
				return returnValue;
			}
		} else {
			console.error("Invalid parameter.");
			return false;
		}
	};
	win.JGantt = JGantt;
})(jQuery, window);